﻿// calculator.cpp : Defines the entry point for the application.
//

#include "calculator.h"

#include <vector>
#include <cmath>

double parseExpression(std::string_view input, size_t &pos)
{
	double result = parseTerm(input, pos); // 首先解析一个项

	skipWhitespace(input, pos); // 跳过运算符前的空白

	while (pos < input.length())
	{
		char op = input[pos];
		if (op == '+' || op == '-')
		{
			pos++; // 跳过运算符
			double next_term = parseTerm(input, pos); // 解析下一个项

			if (op == '+')
			{
				result += next_term;
			}
			else
			{ // op == '-'
				result -= next_term;
			}
			skipWhitespace(input, pos); // 跳过下一个运算符前的空白
		}
		else
		{
			break; // 不是加减运算符，停止循环
		}
	}

	return result;
}

double parseTerm(std::string_view input, size_t &pos)
{
	double result = parsePower(input, pos); // 首先解析一个因子

	skipWhitespace(input, pos); // 跳过运算符前的空白

	while (pos < input.length())
	{
		char op = input[pos];
		if (op == '*' || op == '/' || op == '%')
		{
			pos++; // 跳过运算符

			double next_factor = parseFactor(input, pos); // 解析下一个因子

			if (op == '*')
			{
				result *= next_factor;
			}
			else if (op == '/')
			{
				if (next_factor == 0.0)
				{
					throw std::runtime_error("Division by zero at position " + std::to_string(pos - 1));
				}

				result /= next_factor;
			}
			else if (op == '%')
			{
				// 对于浮点数取模，可以使用 fmod，但通常 % 运算符用于整数
				// 这里简单演示，实际应用可能需要更严格的类型检查或错误处理
				if (next_factor == 0.0)
				{
					throw std::runtime_error("Modulo by zero.");
				}

				result = std::fmod(result, next_factor); // 需要 #include <cmath>
			}

			skipWhitespace(input, pos); // 跳过下一个运算符前的空白
		}
		else
		{
			break; // 不是乘除运算符，停止循环
		}
	}

	return result;
}

double parseFactor(std::string_view input, size_t &pos)
{
	skipWhitespace(input, pos); // 跳过因子前的空白

	if (pos >= input.length())
	{
		throw std::runtime_error("Unexpected end of expression.");
	}

	char current_char = input[pos];

	// 如果是数字，直接解析数字
	if (std::isdigit(current_char) || current_char == '.')
	{
		return parseNumber(input, pos);
	}
	//else if(std::isalpha(current_char))
	//{
	//	size_t name_start = pos;
	//	while (pos < input.length() && (std::isalnum(input[pos]) || input[pos] == '_'))
	//	{
	//		pos++;
	//	}
	//	std::string name = input.substr(name_start, pos - name_start).data();

	//	skipWhitespace(input, pos);
	//	if (pos < input.length() && input[pos] == '(')
	//	{ 
	//		// 可能是函数调用
	//		pos++; // 跳过 '('
	// 
	//		double arg = parseExpression(input, pos); // 解析函数参数

	//		skipWhitespace(input, pos);
	//		if (pos >= input.length() || input[pos] != ')')
	//		{
	//			throw std::runtime_error("Mismatched parentheses: Expected ')' for function call at position " + std::to_string(pos));
	//		}

	//		pos++; // 跳过 ')'

	//		if (name == "sin")
	//		{
	//			return std::sin(arg);
	//		}

	//		if (name == "cos")
	//		{
	//			return std::cos(arg);
	//		}

	//		if (name == "tan")
	//		{
	//			return std::tan(arg);
	//		}

	//		// 自然对数
	//		if (name == "log")
	//		{ 
	//			if (arg <= 0)
	//			{
	//				throw std::runtime_error("Logarithm of non-positive number.");
	//			}

	//			return std::log(arg);
	//		}

	//		// 以10为底的对数
	//		if (name == "log10")
	//		{ 
	//			if (arg <= 0)
	//			{
	//				throw std::runtime_error("Log10 of non-positive number.");
	//			}

	//			return std::log10(arg);
	//		}

	//		// 平方根
	//		if (name == "sqrt")
	//		{ 
	//			if (arg < 0)
	//			{
	//				throw std::runtime_error("Square root of negative number.");
	//			}

	//			return std::sqrt(arg);
	//		}

	//		// ... 可以添加更多函数
	//		throw std::runtime_error("Unknown function: " + name);
	//	}
	//	else
	//	{
	//		// 不是函数调用，是变量
	//		if (variables.count(name))
	//		{
	//			return variables[name];
	//		}
	//		else
	//		{
	//			throw std::runtime_error("Undefined variable: " + name);
	//		}
	//	}
	//}
	// 如果是左括号，递归解析括号内的表达式
	else if (current_char == '(')
	{
		pos++; // 跳过 '('

		double result = parseExpression(input, pos); // 递归调用 parseExpression

		skipWhitespace(input, pos); // 跳过右括号前的空白

		if (pos >= input.length() || input[pos] != ')')
		{
			throw std::runtime_error("Mismatched parentheses: Expected ')' at position " + std::to_string(pos));
		}

		pos++; // 跳过 ')'

		return result;
	}
	// 如果是负号，处理负数
	else if (current_char == '-')
	{
		pos++; // 跳过 '-'

		return -parseFactor(input, pos); // 递归解析负号后面的因子
	}
	// 未预期的字符
	else
	{
		throw std::runtime_error("Unexpected character '" + 
			std::string(1, current_char) + "' at position " + std::to_string(pos));
	}
}

double parsePower(std::string_view input, size_t &pos)
{
	double result = parseFactor(input, pos); // 幂运算的左操作数是因子

	skipWhitespace(input, pos);

	// 幂运算是右结合的
	if (pos < input.length() && input[pos] == '^')
	{
		pos++; // 跳过 '^'

		double exponent = parsePower(input, pos); // 递归调用 parsePower 处理右结合性

		result = std::pow(result, exponent); // 需要 #include <cmath>
	}

	return result;
}

// 辅助函数(处理空白和数字)
void skipWhitespace(std::string_view input, size_t &pos)
{
	while (pos < input.length() && std::isspace(input[pos]))
	{
		pos++;
	}
}

double parseNumber(std::string_view input, size_t &pos)
{
	skipWhitespace(input, pos); // 先跳过数字前的空白

	size_t start_pos = pos;
	// 允许数字以小数点开头，例如 ".5"
	if (pos < input.length() && input[pos] == '.')
	{
		pos++;
	}

	// 读取整数部分
	while (pos < input.length() && std::isdigit(input[pos]))
	{
		pos++;
	}

	// 读取小数部分
	if (pos < input.length() && input[pos] == '.')
	{
		pos++;
		while (pos < input.length() && std::isdigit(input[pos]))
		{
			pos++;
		}
	}

	// 如果没有读取到任何数字字符（包括小数点），则抛出错误
	if (pos == start_pos || (pos == start_pos + 1 && input[start_pos] == '.' && (pos == input.length() || !std::isdigit(input[pos]))))
	{
		throw std::runtime_error("Invalid number format at position " + std::to_string(start_pos));
	}

	// 使用 stod 将子字符串转换为 double
	// 注意：stod 会自动处理空白，但已经手动处理了，所以这里传入的子字符串应该不含前导空白
	// 并且 stod 会自动处理数字解析失败的情况，但已经做了初步检查
	try
	{
		return std::stod(input.substr(start_pos, pos - start_pos).data());
	}
	catch (const std::out_of_range &e)
	{
		throw std::runtime_error("Number out of range at position " + std::to_string(start_pos));
	}
	catch (const std::invalid_argument &e)
	{
		// 理论上，由于前面的isdigit检查，这里不应该发生
		throw std::runtime_error("Invalid number format (stod error) at position " + std::to_string(start_pos));
	}
}

// 主计算函数：封装整个解析和求值过程
double calculate(std::string_view expression)
{
	size_t pos = 0; // 初始化解析位置
	double result = parseExpression(expression, pos); // 从解析表达式开始

	skipWhitespace(expression, pos); // 在表达式末尾跳过任何剩余的空白

	// 最终检查：确保在表达式求值完毕后，pos 已经到达字符串末尾
	// 否则表示有未处理的“垃圾”字符
	if (pos < expression.length())
	{
		throw std::runtime_error(
			"Unexpected characters at end of expression: '" + std::string(expression.substr(pos).data()) + "' at position " + std::to_string(pos));
	}

	return result;
}

void test()
{
	// 定义一系列用于测试的表达式字符串字面量
	std::vector<std::string> test_expressions = {
		"1 + 2",                // 简单加法
		"10 - 5",               // 简单减法
		"2 * 3",                // 简单乘法
		"10 / 2",               // 简单除法
		"1 + 2 * 3",            // 优先级测试: 1 + (2 * 3) = 7
		"(1 + 2) * 3",          // 括号测试: (1 + 2) * 3 = 9
		"10 - 4 / 2 + 1",       // 混合优先级: 10 - (4 / 2) + 1 = 10 - 2 + 1 = 9
		"2 * (3 + 4)",          // 括号与乘法: 2 * (3 + 4) = 14
		"1.5 + 2.5",            // 浮点数加法
		"10 / 3",               // 浮点数除法
		"  5   +   (2 * 3)  ",  // 包含大量空白的表达式
		"1 + 2 * (3 - 1) / 2",  // 复杂混合: 1 + 2 * 2 / 2 = 1 + 4 / 2 = 1 + 2 = 3
		"((1+2))",              // 多层括号
		// 错误测试用例
		"10 / 0",               // 除以零
		"1 + ",                 // 不完整的表达式
		"1 + a",                // 无效字符
		" (1 + 2 ",             // 括号不匹配
		"1 2",                  // 两个数字之间没有运算符
	};

	// 遍历并计算每个测试表达式
	for (const auto &expr : test_expressions)
	{
		std::cout << "Calculating \"" << expr << "\": ";

		try
		{
			double result = calculate(expr);
			// 设置输出精度为小数点后5位
			std::cout << std::fixed << std::setprecision(5) << result << std::endl;
		}
		catch (const std::runtime_error &e)
		{
			// 捕获并打印计算过程中抛出的错误
			std::cerr << "Error: " << e.what() << std::endl;
		}
	}
}

int main()
{
	std::cout << "C++ Calculator. Enter 'exit' to quit." << std::endl;
	std::cout << "Supported operations: +, -, *, /, (), numbers (integers and decimals), unary minus." << std::endl;

	std::string expression;
	while (true)
	{
		std::cout << "Enter expression: ";
		std::getline(std::cin, expression); // 读取整行输入

		if (expression == "exit")
		{
			break;
		}

		if (expression.empty())
		{
			continue; // 空输入，继续
		}

		try
		{
			// 设置浮点数输出精度
			std::cout << std::fixed << std::setprecision(10);

			double result = calculate(expression);

			std::cout << "Result: " << result << std::endl;
		}
		catch (const std::runtime_error &e)
		{
			// 捕获并打印解析过程中抛出的错误
			std::cerr << "Error: " << e.what() << std::endl;
		}
		catch (const std::exception &e)
		{
			// 捕获其他标准异常
			std::cerr << "An unexpected error occurred: " << e.what() << std::endl;
		}
		catch (...)
		{
			// 捕获所有未知异常
			std::cerr << "An unknown error occurred." << std::endl;
		}

		std::cout << std::endl;
	}

	std::cout << "Calculator exited. Goodbye!" << std::endl;

	return 0;
}
